package cn.topcodes.tcsf.admin.service.licence;

import cn.topcode.unicorn.utils.*;
import cn.topcode.unicorn.utils.http.HttpUtil;
import cn.topcodes.tcsf.admin.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 系统授权服务
 * @author Unicorn
 * @date 2017/5/9
 */
@Service
@Transactional(readOnly = true)
public class LicenceServiceImpl implements LicenceService {

    private static Logger logger = LoggerFactory.getLogger(LicenceServiceImpl.class);

    /*授权码密钥*/
    private static final String PASSWORD = "itistcsfpassword";

    /*在线获取授权地址*/
    private String REMOTE_REGISTER_URL = "";

    /*当前系统授权信息*/
    private Licence licence;

    private String registerCode;

    /*系统安装时间*/
    private Date installTime;

    /*最后一次验证时间*/
    private Date lastValidTime;

    @Autowired
    private SystemPropertyService propService;

    /**
     * 从数据库中加载系统安装时间、最后一次验证时间和注册码
     */
    @Override
    @PostConstruct
    public void load() {
        String timeStr = propService.findSysProperty(
                SystemPropertyService.SYS_PROP_INSTALL_TIME,
                String.class,
                DateUtil.formatCurrentDate());
        try {
            installTime = DateUtil.parse(timeStr,DateUtil.YYYY_MM_DD_24H_MM_SS);
        } catch (ParseException e) {
           logger.warn("加载系统安装时间失败",e);
        }
        timeStr = propService.findSysProperty(
                SystemPropertyService.SYS_PROP_LAST_VALID_TIME,
                String.class,
                DateUtil.formatCurrentDate());
        try {
            lastValidTime = DateUtil.parse(timeStr,DateUtil.YYYY_MM_DD_24H_MM_SS);
        } catch (ParseException e) {
            logger.warn("加载最后一次授权验证时间失败",e);
        }
        try {
            String registerCode = propService.findSysProperty(SystemPropertyService.SYS_PROP_REGISTER_CODE,
                    String.class, null);
            if(registerCode != null) {
                loadRegisterCode(registerCode);
            }else {
                logger.error("加载系统授权失败，请联系管理员");
            }
        }catch(Exception e) {
            logger.error("加载系统授权失败-" + e.getMessage() + "，请联系管理员");
        }

    }

    /**
     * 远程授权
     */
    @Override
    @Transactional(readOnly = false)
    public void remoteRegister() throws LicenceException {
        if(licence == null) {
            Map<String, String> params = new HashMap<String, String>();
            params.put("mac", "");
            params.put("diskSn", "");
            params.put("cpuSn", "");
            RemoteRegisterCode remoteRegisterCode = HttpUtil.post(REMOTE_REGISTER_URL, params, RemoteRegisterCode.class);
            if (remoteRegisterCode != null) {
                if ("OK".equals(remoteRegisterCode.getCode())) {
                    register(remoteRegisterCode.getRegisterCode());

                }
            }
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void register(String code) throws LicenceException {
        loadRegisterCode(code);
        Date curDate = new Date();
        this.propService.modifySysProp(SystemPropertyService.SYS_PROP_INSTALL_TIME,
                DateUtil.format(curDate,DateUtil.YYYY_MM_DD_24H_MM_SS));
        this.propService.modifySysProp(SystemPropertyService.SYS_PROP_INSTALL_TIME,
                DateUtil.format(curDate,DateUtil.YYYY_MM_DD_24H_MM_SS));
        this.propService.modifySysProp(SystemPropertyService.SYS_PROP_REGISTER_CODE, code);
    }

    /**
     * 进行系统授权注册
     * @param code	注册码
     */
    @Override
    public void loadRegisterCode(String code) throws LicenceException {
        if(StringUtil.isBlank(code))
            throw new LicenceException("系统未授权");
        byte[] data = ByteUtil.hex2byte(code.toLowerCase());
        if(data == null)
            throw new LicenceException("系统未授权");
        byte[] plainData = AesUtil.decrypt(data, PASSWORD);
        if(plainData == null)
            throw new LicenceException("系统未授权");
        String json = new String(plainData, Charset.forName("utf-8"));
        Licence licence = JsonUtil.parse(json,Licence.class);
        checkLicence(licence, code);
    }

    /**
     * 验证系统是否授权
     */
    @Override
    @Transactional(readOnly = false)
    public void validate() throws LicenceException {
        this.lastValidTime = new Date();
        this.propService.modifySysProp(SystemPropertyService.SYS_PROP_LAST_VALID_TIME,
                DateUtil.format(this.lastValidTime,DateUtil.YYYY_MM_DD_24H_MM_SS));
        if(licence == null) {
            throw new LicenceException("系统尚未授权");
        }

        Date curTime = new Date();
        if(Licence.TYPE_TIME_POINT.equalsIgnoreCase(licence.getType())) {
            //  如果类型为到达时间点过期
            if(lastValidTime != null && curTime.before(lastValidTime)) {
                throw new LicenceException("检测到系统时间被篡改，请修改为正确的时间");
            }
            if(curTime.after(licence.getExpiredTime())) {
                throw new LicenceException("系统授权已过期");
            }
        }else if(Licence.TYPE_TIME_LENGTH.equalsIgnoreCase(licence.getType())) {
            //  如果类型为到达时长过期
            long usedTimeLength = curTime.getTime() - installTime.getTime();
            long totalTimeLength = licence.getEffectiveTimeLength() * (24 * 60 * 60 * 1000);
            if(usedTimeLength >= totalTimeLength) {
                throw new LicenceException("系统授权已过期");
            }
        }
        //  判断cpu
        if(licence.getBindCpu()) {
            String localCpuSn = getMachineInfo().getCpuSn();
            if(!localCpuSn.equalsIgnoreCase(licence.getCpuSn())) {
                throw new LicenceException("授权码无效");
            }
        }
        //  判断硬盘
        if(licence.getBindDisk()) {
            String localDiskSn = getMachineInfo().getDiskSn();
            if(!localDiskSn.equalsIgnoreCase(licence.getDiskSn())) {
                throw new LicenceException("授权码无效");
            }
        }
        //  判断网卡
        if(licence.getBindMac()) {
            String localMac = getMachineInfo().getMac();
            if(!localMac.equalsIgnoreCase(licence.getMac())) {
                throw new LicenceException("授权码无效");
            }
        }
    }

    /**
     * 是否显示试用版本信息
     * @return
     */
    @Override
    public boolean isShowTrial() {
        if(licence == null || licence.getShowTrial()) {
            return true;
        }
        return false;
    }

    /**
     * 获取功能限制参数
     * @return
     */
    @Override
    public Map<String,Boolean> getFunctions() {
        if(licence == null) {
            return new HashMap<String,Boolean>();
        }
        return licence.getFunctions();
    }

    @Override
    public String getMatchineCode() {
        MachineInfo machineInfo = getMachineInfo();
        String json = JsonUtil.toJson(machineInfo);
        byte[] data = AesUtil.encrypt(json,PASSWORD);
        return ByteUtil.byte2Hex(data).toUpperCase();
    }

    @Override
    public MachineInfo getMachineInfo() {
        return new MachineInfo("cpu123456","disk123456","mac123456");
    }

    @Override
    public Licence getLicence() {
        return this.licence;
    }

    @Override
    public String getRegisterCode() {
        return registerCode;
    }

    private void checkLicence(Licence licence, String code) throws LicenceException {
        if(licence != null) {
            if(licence.getBindCpu() == null || licence.getBindDisk() == null || licence.getBindMac() == null
                    || licence.getShowTrial() == null || StringUtil.isBlank(licence.getType())) {
                throw new LicenceException("授权无效");
            }
            if(Licence.TYPE_TIME_POINT.equalsIgnoreCase(licence.getType())) {
                if(licence.getExpiredTime() == null) {
                    throw new LicenceException("授权无效");
                }
                if(licence.getExpiredTime().before(new Date())) {
                    throw new LicenceException("授权已过期");
                }
            }else if(Licence.TYPE_TIME_LENGTH.equalsIgnoreCase(licence.getType())) {
                if(licence.getEffectiveTimeLength() < 0) {
                    throw new LicenceException("授权无效");
                }
                if(licence.getEffectiveTimeLength() >= System.currentTimeMillis() - this.installTime.getTime()) {
                    throw new LicenceException("授权已过期");
                }
            }else {
                throw new LicenceException("授权无效");
            }
        }else {
            throw new LicenceException("授权无效");
        }
        this.licence = licence;
        this.registerCode = code;
    }

}
